summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS1
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua2
-rw-r--r--Nightbuild2008.cmd209
-rw-r--r--Tools/QtBiomeVisualiser/BiomeView.cpp185
-rw-r--r--Tools/QtBiomeVisualiser/BiomeView.h41
-rw-r--r--Tools/QtBiomeVisualiser/ChunkCache.cpp16
-rw-r--r--Tools/QtBiomeVisualiser/ChunkCache.h6
-rw-r--r--Tools/QtBiomeVisualiser/ChunkLoader.h2
-rw-r--r--Tools/QtBiomeVisualiser/ChunkSource.cpp40
-rw-r--r--Tools/QtBiomeVisualiser/ChunkSource.h24
-rw-r--r--Tools/QtBiomeVisualiser/MainWindow.cpp27
-rw-r--r--Tools/QtBiomeVisualiser/MainWindow.h1
-rw-r--r--Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro4
m---------lib/SQLiteCpp0
-rw-r--r--src/Blocks/BlockHandler.cpp2
-rw-r--r--src/ClientHandle.cpp12
-rw-r--r--src/ClientHandle.h14
-rw-r--r--src/Defines.h2
-rw-r--r--src/Entities/Player.cpp29
-rw-r--r--src/Entities/Player.h3
-rw-r--r--src/Generating/BioGen.cpp148
-rw-r--r--src/Protocol/Protocol17x.cpp13
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp2
-rw-r--r--src/Root.cpp4
-rw-r--r--src/Server.cpp7
-rw-r--r--src/Server.h8
-rw-r--r--src/StringUtils.cpp28
-rw-r--r--src/StringUtils.h5
-rw-r--r--src/VoronoiMap.cpp126
-rw-r--r--src/VoronoiMap.h44
-rw-r--r--src/World.h3
31 files changed, 648 insertions, 360 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 925e8f35b..2d911a11d 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -29,5 +29,6 @@ worktycho
xoft
Yeeeeezus (Donated AlchemistVillage prefabs)
Howaner
+Masy98
Please add yourself to this list if you contribute to MCServer.
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua
index 0e7e647d5..66e06cb72 100644
--- a/MCServer/Plugins/Debuggers/Debuggers.lua
+++ b/MCServer/Plugins/Debuggers/Debuggers.lua
@@ -1502,7 +1502,7 @@ function OnPlayerJoined(a_Player)
-- Test composite chat chaining:
a_Player:SendMessage(cCompositeChat()
:AddTextPart("Hello, ")
- :AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2")
+ :AddUrlPart(a_Player:GetName(), "http://www.mc-server.org", "u@2")
:AddSuggestCommandPart(", and welcome.", "/help", "u")
:AddRunCommandPart(" SetDay", "/time set 0")
)
diff --git a/Nightbuild2008.cmd b/Nightbuild2008.cmd
deleted file mode 100644
index bbaea0fb7..000000000
--- a/Nightbuild2008.cmd
+++ /dev/null
@@ -1,209 +0,0 @@
-@echo off
-:: Nightbbuild2008.cmd
-:: This script is run every night to produce a new version of MCServer, backup its PDB files and upload the packages to web.
-:: When run without parameters, this script pauses at the end and waits for a keypress.
-:: To run in an automated scheduler, add any parameter to disable waiting for a keystroke
-::
-:: The sript creates a symbol store (a database of PDB files) that can be used as a single entry in MSVC's symbol path,
-:: then any executable / crashdump built by this script can be debugged and its symbols will be found automatically by MSVC,
-:: without the users needing to specify the build version or anything.
-:: In order to support pruning the symstore, a per-month store is created, so that old months can be removed when no longer needed.
-::
-:: This script expects a few tools on specific paths, you can pass the correct paths for your system as env vars "zip" and "vc"
-:: This script assumes that "git", "symstore" and "touch" are available on PATH.
-:: git comes from msysgit
-:: symstore comes from Microsoft's Debugging Tools for Windows
-:: touch comes from unxtools
-:: This script is locale-dependent, because it parses the output of "time" and "date" shell commands
-
-
-:: 7-zip executable (by default it should be on PATH):
-if %zip%a == a set zip=7z
-
-:: Visual C++ compiler executable name:
-if %vc%a == a set vc="vcbuild.exe"
-
-
-
-
-:: Check that the required environment vars are available:
-if "a%ftppass%" == "a" (
- echo You need to set FTP password in the ftppass environment variable to upload the files
- goto haderror
-)
-if "a%ftpuser%" == "a" (
- echo You need to set FTP username in the ftpuser environment variable to upload the files
- goto haderror
-)
-if "a%ftpsite%" == "a" (
- echo You need to set FTP server in the ftpsite environment variable to upload the files
- goto haderror
-)
-
-
-
-
-:: Get the date and time into vars:
-:: This is locale-dependent!
-For /f "tokens=2-4 delims=/. " %%a in ('date /t') do (
- set MYYEAR=%%c
- set MYMONTH=%%b
- set MYDAY=%%a
-)
-For /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set MYTIME=%%a_%%b)
-
-echo Performing nightbuild of MC-Server
-
-
-
-
-
-set DONOTPAUSE=y
-
-:: Update the sources to the latest revision:
-git pull
-if errorlevel 1 goto haderror
-
-
-
-:: Update the external plugins to the latest revision:
-git submodule update
-if errorlevel 1 goto haderror
-
-
-
-
-:: Get the Git commit ID into an environment var
-For /f "tokens=1 delims=/. " %%a in ('git log -1 --oneline --no-abbrev-commit') do (set COMMITID=%%a)
-if errorlevel 1 goto haderror
-
-
-
-:: Test if the version is already present, using a "tagfile" that we create upon successful build
-set TAGFOLDER=Install\%MYYEAR%_%MYMONTH%\
-set TAGFILE=%TAGFOLDER%built_%COMMITID%.tag
-echo Tag file: %TAGFILE%
-if exist %TAGFILE% (
- echo Latest version already present, bailing out
- goto end
-)
-
-
-
-
-
-:: Configure the sources to use the MSVC2008 compiler:
-cmake -G "Visual Studio 9 2008" .
-if errorlevel 1 goto haderror
-
-
-
-
-
-:: Update the Bindings:
-echo Updating Lua bindings
-del src\Bindings\Bindings.cpp
-del src\Bindings\Bindings.h
-set ALLTOLUA_WAIT=N
-cd src\Bindings
-call AllToLua.bat
-cd ..\..
-
-
-
-
-:: Compile using VC2008 Express. Do a full rebuild.
-echo Setting up VS environment...
-call "%VS90COMNTOOLS%\vsvars32.bat"
-echo Compiling MCServer...
-title MCS Nightbuild
-start "vc" /b /wait /low /min %vc% /r MCServer.sln "Release|Win32"
-if errorlevel 1 goto haderror
-
-
-
-
-:: Generate the .example.ini files by running the server without any ini files:
-cd MCServer
-del groups.ini
-del settings.ini
-del webadmin.ini
-echo stop | MCServer
-cd ..
-
-
-
-:: Copy all the example ini files into the Install folder for zipping:
-copy MCServer\groups.ini Install\groups.example.ini
-copy MCServer\settings.ini Install\settings.example.ini
-copy MCServer\webadmin.ini Install\webadmin.example.ini
-
-
-
-
-:: Use 7-zip to compress the resulting files into a single file:
-set FILESUFFIX=%MYYEAR%_%MYMONTH%_%MYDAY%_%MYTIME%_%COMMITID%
-echo FILESUFFIX=%FILESUFFIX%
-copy MCServer\MCServer.exe Install\MCServer.exe
-cd Install
-%zip% a -mx9 -y MCServer_Win_%FILESUFFIX%.7z -scsWIN -i@Zip2008.list -xr!*.git*
-if errorlevel 1 goto haderror
-cd ..
-
-:: Also pack PDBs into a separate archive:
-%zip% a -mx9 -y Install\PDBs_%FILESUFFIX%.7z -scsWIN @Install\Zip2008_PDBs.list
-if errorlevel 1 goto haderror
-
-
-
-
-
-:: upload to the FTP:
-:upload
-ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% / Install\MCServer_Win_%FILESUFFIX%.7z
-if errorlevel 1 goto haderror
-ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% /PDBs Install\PDBs_%FILESUFFIX%.7z
-if errorlevel 1 goto haderror
-echo Upload finished.
-
-
-
-
-:: Create the tagfile so that we know that this CommitID has been built already
-mkdir %TAGFOLDER%
-touch %TAGFILE%
-
-
-
-
-
-:: Add the symbols to a global symbol cache
-:: We want per-month symbol caches, so that the old ones can be easily deleted
-set SYMBOLS=Symbols\%MYYEAR%_%MYMONTH%\
-echo Storing symbols in %SYMBOLS%
-
-symstore add /f MCServer\MCServer.* /s %SYMBOLS% /t MCServer
-if errorlevel 1 goto haderror
-
-
-
-goto end
-
-
-
-
-:haderror
-echo an error was encountered, check command output above
-pause
-goto finished
-
-
-
-
-
-:end
-if "a%1" == "a" pause
-
-
-
-:finished \ No newline at end of file
diff --git a/Tools/QtBiomeVisualiser/BiomeView.cpp b/Tools/QtBiomeVisualiser/BiomeView.cpp
index be01fd104..bbaccb369 100644
--- a/Tools/QtBiomeVisualiser/BiomeView.cpp
+++ b/Tools/QtBiomeVisualiser/BiomeView.cpp
@@ -8,11 +8,19 @@
+static const int DELTA_STEP = 120; // The normal per-notch wheel delta
+
+
+
+
+
BiomeView::BiomeView(QWidget * parent) :
super(parent),
m_X(0),
m_Z(0),
- m_Zoom(1)
+ m_Zoom(1),
+ m_IsMouseDragging(false),
+ m_MouseWheelDelta(0)
{
// Create the image used for undefined chunks:
int offset = 0;
@@ -33,6 +41,9 @@ BiomeView::BiomeView(QWidget * parent) :
// Add a chunk-update callback mechanism:
connect(&m_Cache, SIGNAL(chunkAvailable(int, int)), this, SLOT(chunkAvailable(int, int)));
+
+ // Allow keyboard interaction:
+ setFocusPolicy(Qt::StrongFocus);
}
@@ -120,6 +131,21 @@ void BiomeView::chunkAvailable(int a_ChunkX, int a_ChunkZ)
+void BiomeView::reload()
+{
+ if (!hasData())
+ {
+ return;
+ }
+ m_Cache.reload();
+
+ redraw();
+}
+
+
+
+
+
void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ)
{
if (!hasData())
@@ -236,9 +262,164 @@ void BiomeView::paintEvent(QPaintEvent * a_Event)
-void BiomeView::queueChunkRender(ChunkPtr a_Chunk)
+void BiomeView::mousePressEvent(QMouseEvent * a_Event)
+{
+ m_LastX = a_Event->x();
+ m_LastY = a_Event->y();
+ m_IsMouseDragging = true;
+}
+
+
+
+
+
+void BiomeView::mouseMoveEvent(QMouseEvent * a_Event)
+{
+ if (m_IsMouseDragging)
+ {
+ // The user is dragging the mouse, move the view around:
+ m_X += (m_LastX - a_Event->x()) / m_Zoom;
+ m_Z += (m_LastY - a_Event->y()) / m_Zoom;
+ m_LastX = a_Event->x();
+ m_LastY = a_Event->y();
+ redraw();
+ return;
+ }
+
+ // TODO: Update the status bar info for the biome currently pointed at
+}
+
+
+
+
+
+void BiomeView::mouseReleaseEvent(QMouseEvent *)
+{
+ m_IsMouseDragging = false;
+}
+
+
+
+
+
+void BiomeView::wheelEvent(QWheelEvent * a_Event)
+{
+ m_MouseWheelDelta += a_Event->delta();
+ while (m_MouseWheelDelta >= DELTA_STEP)
+ {
+ increaseZoom();
+ m_MouseWheelDelta -= DELTA_STEP;
+ }
+ while (m_MouseWheelDelta <= -DELTA_STEP)
+ {
+ decreaseZoom();
+ m_MouseWheelDelta += DELTA_STEP;
+ }
+}
+
+
+
+
+
+void BiomeView::keyPressEvent(QKeyEvent * a_Event)
+{
+ switch (a_Event->key())
+ {
+ case Qt::Key_Up:
+ case Qt::Key_W:
+ {
+ m_Z -= 10.0 / m_Zoom;
+ redraw();
+ break;
+ }
+
+ case Qt::Key_Down:
+ case Qt::Key_S:
+ {
+ m_Z += 10.0 / m_Zoom;
+ redraw();
+ break;
+ }
+
+ case Qt::Key_Left:
+ case Qt::Key_A:
+ {
+ m_X -= 10.0 / m_Zoom;
+ redraw();
+ break;
+ }
+
+ case Qt::Key_Right:
+ case Qt::Key_D:
+ {
+ m_X += 10.0 / m_Zoom;
+ redraw();
+ break;
+ }
+
+ case Qt::Key_PageUp:
+ case Qt::Key_Q:
+ {
+ increaseZoom();
+ break;
+ }
+
+ case Qt::Key_PageDown:
+ case Qt::Key_E:
+ {
+ decreaseZoom();
+ break;
+ }
+ }
+}
+
+
+
+
+
+void BiomeView::decreaseZoom()
{
+ if (m_Zoom > 1.001)
+ {
+ m_Zoom--;
+ if (m_Zoom < 1.0)
+ {
+ // Just crossed the 100%, fixate the 100% threshold:
+ m_Zoom = 1.0;
+ }
+ }
+ else if (m_Zoom > 0.01)
+ {
+ m_Zoom = m_Zoom / 2;
+ }
+ redraw();
+}
+
+
+
+
+void BiomeView::increaseZoom()
+{
+ if (m_Zoom > 0.99)
+ {
+ if (m_Zoom > 20.0)
+ {
+ // Zoom too large
+ return;
+ }
+ m_Zoom++;
+ }
+ else
+ {
+ m_Zoom = m_Zoom * 2;
+ if (m_Zoom > 1.0)
+ {
+ // Just crossed the 100%, fixate the 100% threshold:
+ m_Zoom = 1.0;
+ }
+ }
+ redraw();
}
diff --git a/Tools/QtBiomeVisualiser/BiomeView.h b/Tools/QtBiomeVisualiser/BiomeView.h
index c54c66491..f0521571d 100644
--- a/Tools/QtBiomeVisualiser/BiomeView.h
+++ b/Tools/QtBiomeVisualiser/BiomeView.h
@@ -1,6 +1,7 @@
#pragma once
#include <QWidget>
+#include <memory>
#include "ChunkCache.h"
#include "ChunkSource.h"
@@ -33,12 +34,28 @@ public slots:
/** A specified chunk has become available, redraw it. */
void chunkAvailable(int a_ChunkX, int a_ChunkZ);
+ /** Reloads the current chunk source and redraws the entire workspace. */
+ void reload();
+
protected:
double m_X, m_Z;
- int m_Zoom;
+ double m_Zoom;
+
+ /** Cache for the loaded chunk data. */
ChunkCache m_Cache;
+
+ /** The entire view's contents in an offscreen image. */
QImage m_Image;
+ /** Coords of the mouse for the previous position, used while dragging. */
+ int m_LastX, m_LastY;
+
+ /** Set to true when the user has a mouse button depressed, and is dragging the view. */
+ bool m_IsMouseDragging;
+
+ /** Accumulator for the mouse wheel's delta. When the accumulator hits a threshold, the view zooms. */
+ int m_MouseWheelDelta;
+
/** Data used for rendering a chunk that hasn't been loaded yet */
uchar m_EmptyChunkImage[16 * 16 * 4];
@@ -55,8 +72,26 @@ protected:
/** Paints the entire widget */
virtual void paintEvent(QPaintEvent *) override;
- /** Queues the chunk for rendering. */
- void queueChunkRender(ChunkPtr a_Chunk);
+ /** Called when the user presses any mouse button. */
+ virtual void mousePressEvent(QMouseEvent * a_Event);
+
+ /** Called when the user moves the mouse. */
+ virtual void mouseMoveEvent(QMouseEvent * a_Event);
+
+ /** Called when the user releases a previously held mouse button. */
+ virtual void mouseReleaseEvent(QMouseEvent * a_Event) override;
+
+ /** Called when the user rotates the mouse wheel. */
+ virtual void wheelEvent(QWheelEvent * a_Event) override;
+
+ /** Called when the user presses a key. */
+ virtual void keyPressEvent(QKeyEvent * a_Event) override;
+
+ /** Decreases the zoom level and queues a redraw. */
+ void decreaseZoom();
+
+ /** Increases the zoom level and queues a redraw. */
+ void increaseZoom();
};
diff --git a/Tools/QtBiomeVisualiser/ChunkCache.cpp b/Tools/QtBiomeVisualiser/ChunkCache.cpp
index b2230def0..05c267d30 100644
--- a/Tools/QtBiomeVisualiser/ChunkCache.cpp
+++ b/Tools/QtBiomeVisualiser/ChunkCache.cpp
@@ -76,6 +76,22 @@ void ChunkCache::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource)
+void ChunkCache::reload()
+{
+ assert(m_ChunkSource.get() != nullptr);
+
+ // Reload the chunk source:
+ m_ChunkSource->reload();
+
+ // Clear the cache:
+ QMutexLocker lock(&m_Mtx);
+ m_Cache.clear();
+}
+
+
+
+
+
void ChunkCache::gotChunk(int a_ChunkX, int a_ChunkZ)
{
emit chunkAvailable(a_ChunkX, a_ChunkZ);
diff --git a/Tools/QtBiomeVisualiser/ChunkCache.h b/Tools/QtBiomeVisualiser/ChunkCache.h
index 0efa7fc39..8d198f02f 100644
--- a/Tools/QtBiomeVisualiser/ChunkCache.h
+++ b/Tools/QtBiomeVisualiser/ChunkCache.h
@@ -3,6 +3,7 @@
#include <QObject>
#include <QCache>
#include <QMutex>
+#include <memory>
@@ -36,7 +37,10 @@ public:
void setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource);
/** Returns true iff the chunk source has been initialized. */
- bool hasData(void) const { return (m_ChunkSource.get() != nullptr); }
+ bool hasData() const { return (m_ChunkSource.get() != nullptr); }
+
+ /** Reloads the current chunk source. */
+ void reload();
signals:
void chunkAvailable(int a_ChunkX, int a_ChunkZ);
diff --git a/Tools/QtBiomeVisualiser/ChunkLoader.h b/Tools/QtBiomeVisualiser/ChunkLoader.h
index 3565434b9..4d026a45e 100644
--- a/Tools/QtBiomeVisualiser/ChunkLoader.h
+++ b/Tools/QtBiomeVisualiser/ChunkLoader.h
@@ -1,6 +1,8 @@
#pragma once
+
#include <QObject>
#include <QRunnable>
+#include <memory>
diff --git a/Tools/QtBiomeVisualiser/ChunkSource.cpp b/Tools/QtBiomeVisualiser/ChunkSource.cpp
index 44dcf1fa7..2235816bc 100644
--- a/Tools/QtBiomeVisualiser/ChunkSource.cpp
+++ b/Tools/QtBiomeVisualiser/ChunkSource.cpp
@@ -1,6 +1,8 @@
#include "Globals.h"
#include "ChunkSource.h"
+#include <QThread>
#include "Generating/BioGen.h"
+#include "inifile/iniFile.h"
@@ -101,9 +103,9 @@ public:
for (size_t i = 0; i < ARRAYCOUNT(biomeColors); i++)
{
uchar * color = &biomeToColor[4 * biomeColors[i].m_Biome];
- color[0] = biomeColors[i].m_Color[0];
+ color[0] = biomeColors[i].m_Color[2];
color[1] = biomeColors[i].m_Color[1];
- color[2] = biomeColors[i].m_Color[2];
+ color[2] = biomeColors[i].m_Color[0];
color[3] = 0xff;
}
}
@@ -118,8 +120,8 @@ static void biomesToImage(cChunkDef::BiomeMap & a_Biomes, Chunk::Image & a_Image
{
// Make sure the two arrays are of the same size, compile-time.
// Note that a_Image is actually 4 items per pixel, so the array is 4 times bigger:
- static const char Check1[4 * ARRAYCOUNT(a_Biomes) - ARRAYCOUNT(a_Image) + 1];
- static const char Check2[ARRAYCOUNT(a_Image) - 4 * ARRAYCOUNT(a_Biomes) + 1];
+ static const char Check1[4 * ARRAYCOUNT(a_Biomes) - ARRAYCOUNT(a_Image) + 1] = {};
+ static const char Check2[ARRAYCOUNT(a_Image) - 4 * ARRAYCOUNT(a_Biomes) + 1] = {};
// Convert the biomes into color:
for (size_t i = 0; i < ARRAYCOUNT(a_Biomes); i++)
@@ -138,9 +140,11 @@ static void biomesToImage(cChunkDef::BiomeMap & a_Biomes, Chunk::Image & a_Image
////////////////////////////////////////////////////////////////////////////////
// BioGenSource:
-BioGenSource::BioGenSource(cBiomeGen * a_BiomeGen) :
- m_BiomeGen(a_BiomeGen)
+BioGenSource::BioGenSource(QString a_WorldIniPath) :
+ m_WorldIniPath(a_WorldIniPath),
+ m_Mtx(QMutex::Recursive)
{
+ reload();
}
@@ -149,11 +153,11 @@ BioGenSource::BioGenSource(cBiomeGen * a_BiomeGen) :
void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk)
{
- // TODO: To make use of multicore machines, we need multiple copies of the biomegen
- // Right now we have only one, so we can let only one thread use it (hence the mutex)
- QMutexLocker lock(&m_Mtx);
cChunkDef::BiomeMap biomes;
- m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, biomes);
+ {
+ QMutexLocker lock(&m_Mtx);
+ m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, biomes);
+ }
Chunk::Image img;
biomesToImage(biomes, img);
a_DestChunk->setImage(img);
@@ -162,3 +166,19 @@ void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChu
+
+void BioGenSource::reload()
+{
+ cIniFile ini;
+ ini.ReadFile(m_WorldIniPath.toStdString());
+ int seed = ini.GetValueSetI("Seed", "Seed", 0);
+ bool unused = false;
+ QMutexLocker lock(&m_Mtx);
+ m_BiomeGen.reset(cBiomeGen::CreateBiomeGen(ini, seed, unused));
+ lock.unlock();
+ ini.WriteFile(m_WorldIniPath.toStdString());
+}
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/ChunkSource.h b/Tools/QtBiomeVisualiser/ChunkSource.h
index d6eb2e3cb..868e4a144 100644
--- a/Tools/QtBiomeVisualiser/ChunkSource.h
+++ b/Tools/QtBiomeVisualiser/ChunkSource.h
@@ -1,4 +1,6 @@
#pragma once
+#include <QString>
+#include <QMutex>
#include "Chunk.h"
@@ -7,6 +9,8 @@
// fwd:
class cBiomeGen;
+typedef std::shared_ptr<cBiomeGen> cBiomeGenPtr;
+class cIniFile;
@@ -21,6 +25,9 @@ public:
/** Fills the a_DestChunk with the biomes for the specified coords.
It is expected to be thread-safe and re-entrant. Usually QThread::idealThreadCount() threads are used. */
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) = 0;
+
+ /** Forces a fresh reload of the source. Useful mainly for the generator, whose underlying definition file may have been changed. */
+ virtual void reload() = 0;
};
@@ -32,14 +39,21 @@ class BioGenSource :
public ChunkSource
{
public:
- /** Constructs a new BioGenSource based on the biome generator given.
- Takes ownership of a_BiomeGen */
- BioGenSource(cBiomeGen * a_BiomeGen);
+ /** Constructs a new BioGenSource based on the biome generator that is defined in the specified world.ini file. */
+ BioGenSource(QString a_WorldIniPath);
+ // ChunkSource overrides:
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) override;
+ virtual void reload(void) override;
protected:
- std::shared_ptr<cBiomeGen> m_BiomeGen;
+ /** Path to the world.ini file from which the m_WorldIni is regenerated on reload requests. */
+ QString m_WorldIniPath;
+
+ /** The generator used for generating biomes. */
+ std::unique_ptr<cBiomeGen> m_BiomeGen;
+
+ /** Guards m_BiomeGen against multithreaded access. */
QMutex m_Mtx;
};
@@ -52,7 +66,9 @@ class AnvilSource :
public:
// TODO
+ // ChunkSource overrides:
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) override;
+ virtual void reload() override {}
};
diff --git a/Tools/QtBiomeVisualiser/MainWindow.cpp b/Tools/QtBiomeVisualiser/MainWindow.cpp
index 8b98c0b0e..65d0ccf5e 100644
--- a/Tools/QtBiomeVisualiser/MainWindow.cpp
+++ b/Tools/QtBiomeVisualiser/MainWindow.cpp
@@ -16,11 +16,11 @@
MainWindow::MainWindow(QWidget * parent) :
QMainWindow(parent)
{
- createActions();
- createMenus();
-
m_BiomeView = new BiomeView(this);
setCentralWidget(m_BiomeView);
+
+ createActions();
+ createMenus();
}
@@ -39,19 +39,7 @@ MainWindow::~MainWindow()
void MainWindow::generate()
{
QString worldIni = QFileDialog::getOpenFileName(this, tr("Open world.ini"), QString(), tr("world.ini (world.ini)"));
- cIniFile ini;
- if (!ini.ReadFile(worldIni.toStdString()))
- {
- return;
- }
- int seed = ini.GetValueSetI("Seed", "Seed", 0);
- bool unused = false;
- cBiomeGen * biomeGen = cBiomeGen::CreateBiomeGen(ini, seed, unused);
- if (biomeGen == nullptr)
- {
- return;
- }
- m_BiomeView->setChunkSource(std::shared_ptr<BioGenSource>(new BioGenSource(biomeGen)));
+ m_BiomeView->setChunkSource(std::shared_ptr<BioGenSource>(new BioGenSource(worldIni)));
m_BiomeView->redraw();
}
@@ -80,6 +68,11 @@ void MainWindow::createActions()
m_actOpen->setStatusTip(tr("Open an existing world and display its biomes"));
connect(m_actOpen, SIGNAL(triggered()), this, SLOT(open()));
+ m_actReload = new QAction(tr("&Reload"), this);
+ m_actReload->setShortcut(tr("F5"));
+ m_actReload->setStatusTip(tr("Open an existing world and display its biomes"));
+ connect(m_actReload, SIGNAL(triggered()), m_BiomeView, SLOT(reload()));
+
m_actExit = new QAction(tr("E&xit"), this);
m_actExit->setShortcut(tr("Alt+X"));
m_actExit->setStatusTip(tr("Exit %1").arg(QApplication::instance()->applicationName()));
@@ -96,6 +89,8 @@ void MainWindow::createMenus()
mFile->addAction(m_actGen);
mFile->addAction(m_actOpen);
mFile->addSeparator();
+ mFile->addAction(m_actReload);
+ mFile->addSeparator();
mFile->addAction(m_actExit);
}
diff --git a/Tools/QtBiomeVisualiser/MainWindow.h b/Tools/QtBiomeVisualiser/MainWindow.h
index f6028aff1..b37bf4120 100644
--- a/Tools/QtBiomeVisualiser/MainWindow.h
+++ b/Tools/QtBiomeVisualiser/MainWindow.h
@@ -29,6 +29,7 @@ protected:
// Actions:
QAction * m_actGen;
QAction * m_actOpen;
+ QAction * m_actReload;
QAction * m_actExit;
diff --git a/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro b/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro
index 0329d5607..e6b65e628 100644
--- a/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro
+++ b/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro
@@ -55,8 +55,6 @@ INCLUDEPATH += $$_PRO_FILE_PWD_ \
$$_PRO_FILE_PWD_/../../lib
-CONFIG += STATIC
-
-
+CONFIG += C++11
diff --git a/lib/SQLiteCpp b/lib/SQLiteCpp
-Subproject 203c2fb68bbf871eaf4ca98756a113d74d620de
+Subproject 55edadd56d0d6f506954ad00c3b9a5d425814a2
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index cee2f4b99..30b303cfd 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -427,7 +427,7 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac
if (a_CanDrop)
{
if ((a_Digger != NULL) && (a_Digger->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0))
- {
+ {
switch (m_BlockType)
{
case E_BLOCK_CAKE:
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 487ef3867..43a4161e4 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -312,8 +312,16 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID,
ASSERT(m_Player == NULL);
m_Username = a_Name;
- m_UUID = a_UUID;
- m_Properties = a_Properties;
+
+ // Only assign UUID and properties if not already pre-assigned (BungeeCord sends those in the Handshake packet):
+ if (m_UUID.empty())
+ {
+ m_UUID = a_UUID;
+ }
+ if (m_Properties.empty())
+ {
+ m_Properties = a_Properties;
+ }
// Send login success (if the protocol supports it):
m_Protocol->SendLoginSuccess();
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 05d05e052..b91c3722c 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -64,15 +64,27 @@ public:
const AString & GetIPString(void) const { return m_IPString; } // tolua_export
+ /** Sets the IP string that the client is using. Overrides the IP string that was read from the socket.
+ Used mainly by BungeeCord compatibility code. */
+ void SetIPString(const AString & a_IPString) { m_IPString = a_IPString; }
+
cPlayer * GetPlayer(void) { return m_Player; } // tolua_export
/** Returns the player's UUID, as used by the protocol, in the short form (no dashes) */
const AString & GetUUID(void) const { return m_UUID; } // tolua_export
- void SetUUID(const AString & a_UUID) { m_UUID = a_UUID; }
+ /** Sets the player's UUID, as used by the protocol. Short UUID form (no dashes) is expected.
+ Used mainly by BungeeCord compatibility code - when authenticating is done on the BungeeCord server
+ and the results are passed to MCS running in offline mode. */
+ void SetUUID(const AString & a_UUID) { ASSERT(a_UUID.size() == 32); m_UUID = a_UUID; }
const Json::Value & GetProperties(void) const { return m_Properties; }
+ /** Sets the player's properties, such as skin image and signature.
+ Used mainly by BungeeCord compatibility code - property querying is done on the BungeeCord server
+ and the results are passed to MCS running in offline mode. */
+ void SetProperties(const Json::Value & a_Properties) { m_Properties = a_Properties; }
+
/** Generates an UUID based on the username stored for this client, and stores it in the m_UUID member.
This is used for the offline (non-auth) mode, when there's no UUID source.
Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same.
diff --git a/src/Defines.h b/src/Defines.h
index 78c58034e..6355b75b4 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -115,12 +115,14 @@ enum eGameMode
eGameMode_Survival = 0,
eGameMode_Creative = 1,
eGameMode_Adventure = 2,
+ eGameMode_Spectator = 3,
// Easier-to-use synonyms:
gmNotSet = eGameMode_NotSet,
gmSurvival = eGameMode_Survival,
gmCreative = eGameMode_Creative,
gmAdventure = eGameMode_Adventure,
+ gmSpectator = eGameMode_Spectator,
// These two are used to check GameMode for validity when converting from integers.
gmMax, // Gets automatically assigned
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 55065d550..871311e86 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -451,6 +451,11 @@ void cPlayer::CancelChargingBow(void)
void cPlayer::SetTouchGround(bool a_bTouchGround)
{
+ if (IsGameModeSpectator()) // You can fly through the ground in Spectator
+ {
+ return;
+ }
+
m_bTouchGround = a_bTouchGround;
if (!m_bTouchGround)
@@ -585,7 +590,7 @@ bool cPlayer::Feed(int a_Food, double a_Saturation)
void cPlayer::AddFoodExhaustion(double a_Exhaustion)
{
- if (!IsGameModeCreative())
+ if (!(IsGameModeCreative() || IsGameModeSpectator()))
{
m_FoodExhaustionLevel = std::min(m_FoodExhaustionLevel + a_Exhaustion, 40.0);
}
@@ -823,9 +828,9 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
{
if ((a_TDI.DamageType != dtInVoid) && (a_TDI.DamageType != dtPlugin))
{
- if (IsGameModeCreative())
+ if (IsGameModeCreative() || IsGameModeSpectator())
{
- // No damage / health in creative mode if not void or plugin damage
+ // No damage / health in creative or spectator mode if not void or plugin damage
return false;
}
}
@@ -1043,6 +1048,14 @@ bool cPlayer::IsGameModeAdventure(void) const
+bool cPlayer::IsGameModeSpectator(void) const
+{
+ return (m_GameMode == gmSpectator) || // Either the player is explicitly in Spectator
+ ((m_GameMode == gmNotSet) && m_World->IsGameModeSpectator()); // or they inherit from the world and the world is Adventure
+}
+
+
+
void cPlayer::SetTeam(cTeam * a_Team)
{
@@ -1158,7 +1171,7 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
m_GameMode = a_GameMode;
m_ClientHandle->SendGameMode(a_GameMode);
- if (!IsGameModeCreative())
+ if (!(IsGameModeCreative() || IsGameModeSpectator()))
{
SetFlying(false);
SetCanFly(false);
@@ -1342,6 +1355,7 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos)
void cPlayer::SetVisible(bool a_bVisible)
{
+ // Need to Check if the player or other players are in gamemode spectator, but will break compatibility
if (a_bVisible && !m_bVisible) // Make visible
{
m_bVisible = true;
@@ -1502,6 +1516,11 @@ void cPlayer::TossPickup(const cItem & a_Item)
void cPlayer::TossItems(const cItems & a_Items)
{
+ if (IsGameModeSpectator()) // Players can't toss items in spectator
+ {
+ return;
+ }
+
m_Stats.AddValue(statItemsDropped, (StatValue)a_Items.Size());
double vX = 0, vY = 0, vZ = 0;
@@ -1788,7 +1807,7 @@ bool cPlayer::SaveToDisk()
void cPlayer::UseEquippedItem(int a_Amount)
{
- if (IsGameModeCreative()) // No damage in creative
+ if (IsGameModeCreative() || IsGameModeSpectator()) // No damage in creative or spectator
{
return;
}
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 9821cc6d9..d64dd6b99 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -171,6 +171,9 @@ public:
/** Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world */
bool IsGameModeAdventure(void) const;
+ /** Returns true if the player is in Spectator mode, either explicitly, or by inheriting from current world */
+ bool IsGameModeSpectator(void) const;
+
AString GetIP(void) const { return m_IP; } // tolua_export
/** Returns the associated team, NULL if none */
diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp
index 60ad4e3eb..217ca8f80 100644
--- a/src/Generating/BioGen.cpp
+++ b/src/Generating/BioGen.cpp
@@ -13,72 +13,6 @@
////////////////////////////////////////////////////////////////////////////////
-// cBiomeGen:
-
-cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault)
-{
- AString BiomeGenName = a_IniFile.GetValueSet("Generator", "BiomeGen", "");
- if (BiomeGenName.empty())
- {
- LOGWARN("[Generator] BiomeGen value not set in world.ini, using \"MultiStepMap\".");
- BiomeGenName = "MultiStepMap";
- }
-
- cBiomeGen * res = NULL;
- a_CacheOffByDefault = false;
- if (NoCaseCompare(BiomeGenName, "constant") == 0)
- {
- res = new cBioGenConstant;
- a_CacheOffByDefault = true; // we're generating faster than a cache would retrieve data :)
- }
- else if (NoCaseCompare(BiomeGenName, "checkerboard") == 0)
- {
- res = new cBioGenCheckerboard;
- a_CacheOffByDefault = true; // we're (probably) generating faster than a cache would retrieve data
- }
- else if (NoCaseCompare(BiomeGenName, "voronoi") == 0)
- {
- res = new cBioGenVoronoi(a_Seed);
- }
- else if (NoCaseCompare(BiomeGenName, "distortedvoronoi") == 0)
- {
- res = new cBioGenDistortedVoronoi(a_Seed);
- }
- else if (NoCaseCompare(BiomeGenName, "twolevel") == 0)
- {
- res = new cBioGenTwoLevel(a_Seed);
- }
- else
- {
- if (NoCaseCompare(BiomeGenName, "multistepmap") != 0)
- {
- LOGWARNING("Unknown BiomeGen \"%s\", using \"MultiStepMap\" instead.", BiomeGenName.c_str());
- }
- res = new cBioGenMultiStepMap(a_Seed);
-
- /*
- // Performance-testing:
- LOGINFO("Measuring performance of cBioGenMultiStepMap...");
- clock_t BeginTick = clock();
- for (int x = 0; x < 5000; x++)
- {
- cChunkDef::BiomeMap Biomes;
- res->GenBiomes(x * 5, x * 5, Biomes);
- }
- clock_t Duration = clock() - BeginTick;
- LOGINFO("cBioGenMultiStepMap for 5000 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
- //*/
- }
- res->InitializeBiomeGen(a_IniFile);
-
- return res;
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
// cBioGenConstant:
void cBioGenConstant::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap)
@@ -402,8 +336,13 @@ void cBioGenVoronoi::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap &
void cBioGenVoronoi::InitializeBiomeGen(cIniFile & a_IniFile)
{
super::InitializeBiomeGen(a_IniFile);
- m_Voronoi.SetCellSize(a_IniFile.GetValueSetI("Generator", "VoronoiCellSize", 64));
- InitializeBiomes (a_IniFile.GetValueSet ("Generator", "VoronoiBiomes", ""));
+ int CellSize = a_IniFile.GetValueSetI("Generator", "VoronoiCellSize", 128);
+ int JitterSize = a_IniFile.GetValueSetI("Generator", "VoronoiJitterSize", CellSize);
+ int OddRowOffset = a_IniFile.GetValueSetI("Generator", "VoronoiOddRowOffset", 0);
+ m_Voronoi.SetCellSize(CellSize);
+ m_Voronoi.SetJitterSize(JitterSize);
+ m_Voronoi.SetOddRowOffset(OddRowOffset);
+ InitializeBiomes(a_IniFile.GetValueSet ("Generator", "VoronoiBiomes", ""));
}
@@ -846,9 +785,10 @@ void cBioGenTwoLevel::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap
{
for (int x = 0; x < cChunkDef::Width; x++)
{
- int MinDist1, MinDist2;
- int BiomeGroup = m_VoronoiLarge.GetValueAt(DistortX[x][z], DistortZ[x][z], MinDist1, MinDist2) / 7;
- int BiomeIdx = m_VoronoiSmall.GetValueAt(DistortX[x][z], DistortZ[x][z], MinDist1, MinDist2) / 11;
+ int SeedX, SeedZ, MinDist2;
+ int BiomeGroup = m_VoronoiLarge.GetValueAt(DistortX[x][z], DistortZ[x][z], SeedX, SeedZ, MinDist2) / 7;
+ int BiomeIdx = m_VoronoiSmall.GetValueAt(DistortX[x][z], DistortZ[x][z], SeedX, SeedZ, MinDist2) / 11;
+ int MinDist1 = (DistortX[x][z] - SeedX) * (DistortX[x][z] - SeedX) + (DistortZ[x][z] - SeedZ) * (DistortZ[x][z] - SeedZ);
cChunkDef::SetBiome(a_BiomeMap, x, z, SelectBiome(BiomeGroup, BiomeIdx, (MinDist1 < MinDist2 / 4) ? 0 : 1));
}
}
@@ -987,3 +927,69 @@ void cBioGenTwoLevel::InitializeBiomeGen(cIniFile & a_IniFile)
+
+////////////////////////////////////////////////////////////////////////////////
+// cBiomeGen:
+
+cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault)
+{
+ AString BiomeGenName = a_IniFile.GetValueSet("Generator", "BiomeGen", "");
+ if (BiomeGenName.empty())
+ {
+ LOGWARN("[Generator] BiomeGen value not set in world.ini, using \"MultiStepMap\".");
+ BiomeGenName = "MultiStepMap";
+ }
+
+ cBiomeGen * res = NULL;
+ a_CacheOffByDefault = false;
+ if (NoCaseCompare(BiomeGenName, "constant") == 0)
+ {
+ res = new cBioGenConstant;
+ a_CacheOffByDefault = true; // we're generating faster than a cache would retrieve data :)
+ }
+ else if (NoCaseCompare(BiomeGenName, "checkerboard") == 0)
+ {
+ res = new cBioGenCheckerboard;
+ a_CacheOffByDefault = true; // we're (probably) generating faster than a cache would retrieve data
+ }
+ else if (NoCaseCompare(BiomeGenName, "voronoi") == 0)
+ {
+ res = new cBioGenVoronoi(a_Seed);
+ }
+ else if (NoCaseCompare(BiomeGenName, "distortedvoronoi") == 0)
+ {
+ res = new cBioGenDistortedVoronoi(a_Seed);
+ }
+ else if (NoCaseCompare(BiomeGenName, "twolevel") == 0)
+ {
+ res = new cBioGenTwoLevel(a_Seed);
+ }
+ else
+ {
+ if (NoCaseCompare(BiomeGenName, "multistepmap") != 0)
+ {
+ LOGWARNING("Unknown BiomeGen \"%s\", using \"MultiStepMap\" instead.", BiomeGenName.c_str());
+ }
+ res = new cBioGenMultiStepMap(a_Seed);
+
+ /*
+ // Performance-testing:
+ LOGINFO("Measuring performance of cBioGenMultiStepMap...");
+ clock_t BeginTick = clock();
+ for (int x = 0; x < 5000; x++)
+ {
+ cChunkDef::BiomeMap Biomes;
+ res->GenBiomes(x * 5, x * 5, Biomes);
+ }
+ clock_t Duration = clock() - BeginTick;
+ LOGINFO("cBioGenMultiStepMap for 5000 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
+ //*/
+ }
+ res->InitializeBiomeGen(a_IniFile);
+
+ return res;
+}
+
+
+
+
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 05935fbe1..2fbc58541 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -102,6 +102,19 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
m_IsEncrypted(false),
m_LastSentDimension(dimNotSet)
{
+ // BungeeCord handling:
+ // If BC is setup with ip_forward == true, it sends additional data in the login packet's ServerAddress field:
+ // hostname\00ip-address\00uuid\00profile-properties-as-json
+ AStringVector Params;
+ if (cRoot::Get()->GetServer()->ShouldAllowBungeeCord() && SplitZeroTerminatedStrings(a_ServerAddress, Params) && (Params.size() == 4))
+ {
+ LOGD("Player at %s connected via BungeeCord", Params[1].c_str());
+ m_ServerAddress = Params[0];
+ m_Client->SetIPString(Params[1]);
+ m_Client->SetUUID(cMojangAPI::MakeUUIDShort(Params[2]));
+ m_Client->SetProperties(Params[3]);
+ }
+
// Create the comm log file, if so requested:
if (g_ShouldLogCommIn || g_ShouldLogCommOut)
{
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 36e791fc7..4516975bf 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -28,7 +28,7 @@
cProtocolRecognizer::cProtocolRecognizer(cClientHandle * a_Client) :
super(a_Client),
m_Protocol(NULL),
- m_Buffer(512)
+ m_Buffer(8192) // We need a larger buffer to support BungeeCord - it sends one huge packet at the start
{
}
diff --git a/src/Root.cpp b/src/Root.cpp
index 86a497a76..966a9b4ba 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -113,8 +113,8 @@ void cRoot::Start(void)
LOG("--- Started Log ---\n");
#ifdef BUILD_ID
- LOG("MCServer " BUILD_SERIES_NAME " build id: " BUILD_ID );
- LOG("from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME );
+ LOG("MCServer " BUILD_SERIES_NAME " build id: " BUILD_ID);
+ LOG("from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME);
#endif
cDeadlockDetect dd;
diff --git a/src/Server.cpp b/src/Server.cpp
index 069e2a169..969ffd693 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -259,6 +259,13 @@ bool cServer::InitServer(cIniFile & a_SettingsIni)
m_ServerID = sid.str();
m_ServerID.resize(16, '0');
}
+
+ // Check if both BungeeCord and online mode are on, if so, warn the admin:
+ m_ShouldAllowBungeeCord = a_SettingsIni.GetValueSetB("Authentication", "AllowBungeeCord", false);
+ if (m_ShouldAllowBungeeCord && m_ShouldAuthenticate)
+ {
+ LOGWARNING("WARNING: BungeeCord is allowed and server set to online mode. This is unsafe and will not work properly. Disable either authentication or BungeeCord in settings.ini.");
+ }
m_ShouldLoadOfflinePlayerData = a_SettingsIni.GetValueSetB("PlayerData", "LoadOfflinePlayerData", false);
m_ShouldLoadNamedPlayerData = a_SettingsIni.GetValueSetB("PlayerData", "LoadNamedPlayerData", true);
diff --git a/src/Server.h b/src/Server.h
index f20e6932f..6d659fa40 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -131,6 +131,11 @@ public: // tolua_export
Loaded from the settings.ini [PlayerData].LoadNamedPlayerData setting. */
bool ShouldLoadNamedPlayerData(void) const { return m_ShouldLoadNamedPlayerData; }
+ /** Returns true if BungeeCord logins (that specify the player's UUID) are allowed.
+ Read from settings, admins should set this to true only when they chain to BungeeCord,
+ it makes the server vulnerable to identity theft through direct connections. */
+ bool ShouldAllowBungeeCord(void) const { return m_ShouldAllowBungeeCord; }
+
private:
friend class cRoot; // so cRoot can create and destroy cServer
@@ -230,6 +235,9 @@ private:
This allows a seamless transition from name-based to UUID-based player storage.
Loaded from the settings.ini [PlayerData].LoadNamedPlayerData setting. */
bool m_ShouldLoadNamedPlayerData;
+
+ /** True if BungeeCord handshake packets (with player UUID) should be accepted. */
+ bool m_ShouldAllowBungeeCord;
cServer(void);
diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp
index 5f88cbf64..73147eebc 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -869,3 +869,31 @@ void SetBEInt(char * a_Mem, Int32 a_Value)
+
+bool SplitZeroTerminatedStrings(const AString & a_Strings, AStringVector & a_Output)
+{
+ a_Output.clear();
+ size_t size = a_Strings.size();
+ size_t start = 0;
+ bool res = false;
+ for (size_t i = 0; i < size; i++)
+ {
+ if (a_Strings[i] == 0)
+ {
+ a_Output.push_back(a_Strings.substr(start, i - start));
+ start = i + 1;
+ res = true;
+ }
+ }
+ if (start < size)
+ {
+ a_Output.push_back(a_Strings.substr(start, size - start));
+ res = true;
+ }
+
+ return res;
+}
+
+
+
+
diff --git a/src/StringUtils.h b/src/StringUtils.h
index 72a90a8c2..a76894d05 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -99,6 +99,11 @@ extern int GetBEInt(const char * a_Mem);
/// Writes four bytes to the specified memory location so that they interpret as BigEndian int
extern void SetBEInt(char * a_Mem, Int32 a_Value);
+/** Splits a string that has embedded \0 characters, on those characters.
+a_Output is first cleared and then each separate string is pushed back into a_Output.
+Returns true if there are at least two strings in a_Output (there was at least one \0 separator). */
+extern bool SplitZeroTerminatedStrings(const AString & a_Strings, AStringVector & a_Output);
+
/// Parses any integer type. Checks bounds and returns errors out of band.
template <class T>
bool StringToInteger(const AString & a_str, T & a_Num)
diff --git a/src/VoronoiMap.cpp b/src/VoronoiMap.cpp
index 5efd09c01..5ad634fe4 100644
--- a/src/VoronoiMap.cpp
+++ b/src/VoronoiMap.cpp
@@ -10,11 +10,13 @@
-cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize) :
+cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize, int a_JitterSize) :
m_Noise1(a_Seed + 1),
m_Noise2(a_Seed + 2),
m_Noise3(a_Seed + 3),
- m_CellSize(a_CellSize),
+ m_CellSize(std::max(a_CellSize, 2)),
+ m_JitterSize(Clamp(a_JitterSize, 1, a_CellSize)),
+ m_OddRowOffset(0),
m_CurrentCellX(9999999), // Cell coords that are definitely out of the range for normal generator, so that the first query will overwrite them
m_CurrentCellZ(9999999)
{
@@ -26,7 +28,29 @@ cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize) :
void cVoronoiMap::SetCellSize(int a_CellSize)
{
+ a_CellSize = std::max(a_CellSize, 2); // Cell size must be at least 2
m_CellSize = a_CellSize;
+
+ // For compatibility with previous version, which didn't have the jitter, we set jitter here as well.
+ m_JitterSize = a_CellSize;
+}
+
+
+
+
+
+void cVoronoiMap::SetJitterSize(int a_JitterSize)
+{
+ m_JitterSize = Clamp(a_JitterSize, 1, m_CellSize);
+}
+
+
+
+
+
+void cVoronoiMap::SetOddRowOffset(int a_OddRowOffset)
+{
+ m_OddRowOffset = Clamp(a_OddRowOffset, -m_CellSize, m_CellSize);
}
@@ -35,8 +59,8 @@ void cVoronoiMap::SetCellSize(int a_CellSize)
int cVoronoiMap::GetValueAt(int a_X, int a_Y)
{
- int MinDist1, MinDist2;
- return GetValueAt(a_X, a_Y, MinDist1, MinDist2);
+ int SeedX, SeedY, MinDist2;
+ return GetValueAt(a_X, a_Y, SeedX, SeedY, MinDist2);
}
@@ -45,41 +69,47 @@ int cVoronoiMap::GetValueAt(int a_X, int a_Y)
int cVoronoiMap::GetValueAt(int a_X, int a_Y, int & a_MinDist)
{
- int MinDist2;
- return GetValueAt(a_X, a_Y, a_MinDist, MinDist2);
+ int SeedX, SeedY, MinDist2;
+ int res = GetValueAt(a_X, a_Y, SeedX, SeedY, MinDist2);
+ a_MinDist = (a_X - SeedX) * (a_X - SeedX) + (a_Y - SeedY) * (a_Y - SeedY);
+ return res;
}
-int cVoronoiMap::GetValueAt(int a_X, int a_Y, int & a_MinDist1, int & a_MinDist2)
+int cVoronoiMap::GetValueAt(
+ int a_X, int a_Y, // Coords to query
+ int & a_NearestSeedX, int & a_NearestSeedY, // Coords of the closest cell
+ int & a_MinDist2 // Distance to the second closest cell
+)
{
- // Note that due to historical reasons, the algorithm uses XZ coords, while the input uses XY coords.
- // This is because the algorithm was first implemented directly in the biome generators which use MC coords.
-
int CellX = a_X / m_CellSize;
- int CellZ = a_Y / m_CellSize;
+ int CellY = a_Y / m_CellSize;
- UpdateCell(CellX, CellZ);
+ UpdateCell(CellX, CellY);
// Get 5x5 neighboring cell seeds, compare distance to each. Return the value in the minumim-distance cell
+ int NearestSeedX = 0, NearestSeedY = 0;
int MinDist = m_CellSize * m_CellSize * 16; // There has to be a cell closer than this
int MinDist2 = MinDist;
int res = 0; // Will be overriden
for (int x = 0; x < 5; x++)
{
- for (int z = 0; z < 5; z++)
+ for (int y = 0; y < 5; y++)
{
- int SeedX = m_SeedX[x][z];
- int SeedZ = m_SeedZ[x][z];
+ int SeedX = m_SeedX[x][y];
+ int SeedY = m_SeedZ[x][y];
- int Dist = (SeedX - a_X) * (SeedX - a_X) + (SeedZ - a_Y) * (SeedZ - a_Y);
+ int Dist = (SeedX - a_X) * (SeedX - a_X) + (SeedY - a_Y) * (SeedY - a_Y);
if (Dist < MinDist)
{
+ NearestSeedX = SeedX;
+ NearestSeedY = SeedY;
MinDist2 = MinDist;
MinDist = Dist;
- res = m_Noise3.IntNoise2DInt(x + CellX - 2, z + CellZ - 2);
+ res = m_Noise3.IntNoise2DInt(x + CellX - 2, y + CellY - 2);
}
else if (Dist < MinDist2)
{
@@ -88,7 +118,8 @@ int cVoronoiMap::GetValueAt(int a_X, int a_Y, int & a_MinDist1, int & a_MinDist2
} // for z
} // for x
- a_MinDist1 = MinDist;
+ a_NearestSeedX = NearestSeedX;
+ a_NearestSeedY = NearestSeedY;
a_MinDist2 = MinDist2;
return res;
}
@@ -97,6 +128,58 @@ int cVoronoiMap::GetValueAt(int a_X, int a_Y, int & a_MinDist1, int & a_MinDist2
+void cVoronoiMap::FindNearestSeeds(
+ int a_X, int a_Y,
+ int & a_NearestSeedX, int & a_NearestSeedY,
+ int & a_SecondNearestSeedX, int & a_SecondNearestSeedY
+)
+{
+ int CellX = a_X / m_CellSize;
+ int CellY = a_Y / m_CellSize;
+
+ UpdateCell(CellX, CellY);
+
+ // Get 5x5 neighboring cell seeds, compare distance to each. Return the value in the minumim-distance cell
+ int NearestSeedX = 0, NearestSeedY = 0;
+ int SecondNearestSeedX = 0, SecondNearestSeedY = 0;
+ int MinDist = m_CellSize * m_CellSize * 16; // There has to be a cell closer than this
+ int MinDist2 = MinDist;
+ for (int x = 0; x < 5; x++)
+ {
+ for (int y = 0; y < 5; y++)
+ {
+ int SeedX = m_SeedX[x][y];
+ int SeedY = m_SeedZ[x][y];
+
+ int Dist = (SeedX - a_X) * (SeedX - a_X) + (SeedY - a_Y) * (SeedY - a_Y);
+ if (Dist < MinDist)
+ {
+ SecondNearestSeedX = NearestSeedX;
+ SecondNearestSeedY = NearestSeedY;
+ MinDist2 = MinDist;
+ NearestSeedX = SeedX;
+ NearestSeedY = SeedY;
+ MinDist = Dist;
+ }
+ else if (Dist < MinDist2)
+ {
+ SecondNearestSeedX = SeedX;
+ SecondNearestSeedY = SeedY;
+ MinDist2 = Dist;
+ }
+ } // for z
+ } // for x
+
+ a_NearestSeedX = NearestSeedX;
+ a_NearestSeedY = NearestSeedY;
+ a_SecondNearestSeedX = SecondNearestSeedX;
+ a_SecondNearestSeedY = SecondNearestSeedY;
+}
+
+
+
+
+
void cVoronoiMap::UpdateCell(int a_CellX, int a_CellZ)
{
// If the specified cell is currently cached, bail out:
@@ -111,12 +194,13 @@ void cVoronoiMap::UpdateCell(int a_CellX, int a_CellZ)
for (int x = 0; x < 5; x++)
{
int BaseX = (NoiseBaseX + x) * m_CellSize;
+ int OddRowOffset = ((NoiseBaseX + x) & 0x01) * m_OddRowOffset;
for (int z = 0; z < 5; z++)
{
- int OffsetX = (m_Noise1.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_CellSize;
- int OffsetZ = (m_Noise2.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_CellSize;
+ int OffsetX = (m_Noise1.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_JitterSize;
+ int OffsetZ = (m_Noise2.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_JitterSize;
m_SeedX[x][z] = BaseX + OffsetX;
- m_SeedZ[x][z] = (NoiseBaseZ + z) * m_CellSize + OffsetZ;
+ m_SeedZ[x][z] = (NoiseBaseZ + z) * m_CellSize + OddRowOffset + OffsetZ;
} // for z
} // for x
m_CurrentCellX = a_CellX;
diff --git a/src/VoronoiMap.h b/src/VoronoiMap.h
index 84cf206e9..dfb11e9ce 100644
--- a/src/VoronoiMap.h
+++ b/src/VoronoiMap.h
@@ -18,19 +18,40 @@
class cVoronoiMap
{
public:
- cVoronoiMap(int a_Seed, int a_CellSize = 128);
+ cVoronoiMap(int a_Seed, int a_CellSize = 128, int a_JitterSize = 128);
- /// Sets the cell size used for generating the Voronoi seeds
+ /** Sets both the cell size and jitter size used for generating the Voronoi seeds. */
void SetCellSize(int a_CellSize);
+
+ /** Sets the jitter size. Clamps it to current cell size. */
+ void SetJitterSize(int a_JitterSize);
+
+ /** Sets the offset that is added to each odd row of cells.
+ This offset makes the voronoi cells align to a non-grid.
+ Clamps the value to [-m_CellSize, +m_CellSize]. */
+ void SetOddRowOffset(int a_OddRowOffset);
- /// Returns the value in the cell into which the specified point lies
+ /** Returns the value in the cell into which the specified point lies. */
int GetValueAt(int a_X, int a_Y);
- /// Returns the value in the cell into which the specified point lies, and the distance to the nearest Voronoi seed
+ /** Returns the value in the cell into which the specified point lies,
+ and the distance to the nearest Voronoi seed. */
int GetValueAt(int a_X, int a_Y, int & a_MinDistance);
- /// Returns the value in the cell into which the specified point lies, and the distances to the 2 nearest Voronoi seeds. Uses a cache
- int GetValueAt(int a_X, int a_Y, int & a_MinDistance1, int & a_MinDistance2);
+ /** Returns the value in the cell into which the specified point lies,
+ and the distances to the 2 nearest Voronoi seeds. Uses a cache. */
+ int GetValueAt(
+ int a_X, int a_Y, // Coords to query
+ int & a_NearestSeedX, int & a_NearestSeedY, // Coords of the closest cell's seed
+ int & a_MinDist2 // Distance to the second closest cell's seed
+ );
+
+ /** Finds the nearest and second nearest seeds, returns their coords. */
+ void FindNearestSeeds(
+ int a_X, int a_Y,
+ int & a_NearestSeedX, int & a_NearestSeedY,
+ int & a_SecondNearestSeedX, int & a_SecondNearestSeedY
+ );
protected:
/// The noise used for generating Voronoi seeds
@@ -38,8 +59,17 @@ protected:
cNoise m_Noise2;
cNoise m_Noise3;
- /// Size of the Voronoi cells (avg X/Y distance between the seeds)
+ /** Size of the Voronoi cells (avg X/Y distance between the seeds). Expected to be at least 2. */
int m_CellSize;
+
+ /** The amount that the cell seeds may be offset from the grid.
+ Expected to be at least 1 and less than m_CellSize. */
+ int m_JitterSize;
+
+ /** The constant amount that the cell seeds of every odd row will be offset from the grid.
+ This allows us to have non-rectangular grids.
+ Expected to be between -m_CellSize and +m_CellSize. */
+ int m_OddRowOffset;
/** The X coordinate of the currently cached cell neighborhood */
int m_CurrentCellX;
diff --git a/src/World.h b/src/World.h
index 391124a03..eee0ced54 100644
--- a/src/World.h
+++ b/src/World.h
@@ -188,6 +188,9 @@ public:
/** Returns true if the world is in Adventure mode */
bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); }
+ /** Returns true if the world is in Spectator mode */
+ bool IsGameModeSpectator(void) const { return (m_GameMode == gmSpectator); }
+
bool IsPVPEnabled(void) const { return m_bEnabledPVP; }
bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; }